#include "llcomp_llc.h"

void loopParallelFor1_support (double *x, double *r, double *p, int *_cols,
			       int *_i, double *z);
void
loopParallelFor1_support (double *x, double *r, double *p, int *_cols,
			  int *_i, double *z)
{
  int cols = *_cols;
  int i = *_i;
  /* Begin template: forall_init_unit.tmpl */

/* $0 => Variable del bucle
 * loop_initial => Valor inicial de la variable del bucle B
 * loop_finalice => Valor final de la variable del bucle C
 */

  {
    int llc_meanT, llc_rnT;
    register int llc_i;

    llc_nT = ((cols - 1) - (0) + 1);
    /* Medium number of tasks */
    llc_meanT = llc_nT / LLC_NUMPROCESSORS;
    /* Number of unassigned tasks */
    llc_rnT = llc_nT % LLC_NUMPROCESSORS;

    LLC_CHECK_MALLOC (llc_F, (LLC_NUMPROCESSORS + 1), int);

    llc_F[0] = 0;
    for (llc_i = 1; llc_i < (LLC_NUMPROCESSORS + 1); llc_i++)
      {
	llc_F[llc_i] =
	  llc_F[llc_i - 1] + llc_meanT + (((llc_i - 1) < llc_rnT) ? 1 : 0);
      }
  }

/* End template: forall_init_unit.tmpl */
/* Begin template: forall_exec_unit.tmpl */

/* loop_var => Variable del bucle
 * loop_initial => Valor inicial de la variable del bucle
 * loop_stmt => Bloque del bucle
 */

  {
    int llc_nP;
    int llc_grp_save;
    register int llc_i;

    llc_nP = LLC_NUMPROCESSORS;
    llc_grp_save = LLC_NAME;
    LLC_NUMPROCESSORS = 1;
    LLC_NAME = 0;

    i = (0) + llc_F[llc_grp_save];
    for (llc_i = 0; llc_i < LLC_PROCSGRP (llc_grp_save); llc_i++, i++)
      {

	{

	  p[i] = r[i] = x[i];
	  z[i] = 0.0;
	}

	;
      }

    LLC_NAME = llc_grp_save;
    LLC_NUMPROCESSORS = llc_nP;
  }

/* End template: forall_exec_unit.tmpl */
/* Begin template: forall_comm_res_unit.tmpl */

/* loop_var => Variable del bucle
 * loop_initial => Valor inicial de la variable del bucle
 * loop_finalice => Valor final de la variable del bucle
 * forall_comm_res_init => template dinamico que se utiliza para reservar memoria para las comunicaciones
 * forall_comm_res_pack => template dinamico que se utiliza para realizar las comunicaciones
 */

  {
    register int llc_i, llc_j;
    long llc_buf_size = 0, llc_size_tmp = 0;
    char *llc_buf = NULL, *llc_buf_ptr = NULL;

    for (llc_i = 0; llc_i < LLC_NUMPROCESSORS; llc_i++)
      {
	llc_size_tmp = 0;
	for (llc_j = 0, i = (0) + llc_F[llc_i]; llc_j < LLC_PROCSGRP (llc_i);
	     llc_j++, i++)
	  {
	    llc_size_tmp += (1) * sizeof ((&p[i])[0]);
	    llc_size_tmp += (1) * sizeof ((&z[i])[0]);
	    llc_size_tmp += (1) * sizeof ((&r[i])[0]);

	  }
	llc_buf_size = LLC_MAX (llc_buf_size, llc_size_tmp);
      }

    if (llc_buf_size > 0)
      {
	LLC_CHECK_MALLOC (llc_buf, llc_buf_size, char);
	for (llc_i = 0; llc_i < LLC_NUMPROCESSORS; llc_i++)
	  {
	    if (llc_i == LLC_NAME)
	      {
		llc_buf_ptr = llc_buf;
		for (llc_j = 0, i = (0) + llc_F[llc_i];
		     llc_j < LLC_PROCSGRP (llc_i); llc_j++, i++)
		  {
		    /* Packing &p[i]... */
		    memcpy (llc_buf_ptr, &p[i], (1) * sizeof ((&p[i])[0]));
		    llc_buf_ptr += (1) * sizeof ((&p[i])[0]);
            /* Packing &z[i]... */
		    memcpy (llc_buf_ptr, &z[i], (1) * sizeof ((&z[i])[0]));
		    llc_buf_ptr += (1) * sizeof ((&z[i])[0]);
            /* Packing &r[i]... */
		    memcpy (llc_buf_ptr, &r[i], (1) * sizeof ((&r[i])[0]));
		    llc_buf_ptr += (1) * sizeof ((&r[i])[0]);

		  }
		MPI_Bcast (llc_buf, (llc_buf_ptr - llc_buf), MPI_BYTE, llc_i,
			   *llc_CurrentGroup);
	      }
	    else
	      {
		llc_size_tmp = 0;
		for (llc_j = 0, i = (0) + llc_F[llc_i];
		     llc_j < LLC_PROCSGRP (llc_i); llc_j++, i++)
		  {
		    llc_size_tmp += (1) * sizeof ((&p[i])[0]);
		    llc_size_tmp += (1) * sizeof ((&z[i])[0]);
		    llc_size_tmp += (1) * sizeof ((&r[i])[0]);

		  }
		MPI_Bcast (llc_buf, llc_size_tmp, MPI_BYTE, llc_i,
			   *llc_CurrentGroup);
		llc_buf_ptr = llc_buf;
		for (llc_j = 0, i = (0) + llc_F[llc_i];
		     llc_j < LLC_PROCSGRP (llc_i); llc_j++, i++)
		  {
		    /* Unpacking &p[i]... */
		    memcpy (&p[i], llc_buf_ptr, (1) * sizeof ((&p[i])[0]));
		    llc_buf_ptr += (1) * sizeof ((&p[i])[0]);

		    /* Unpacking &z[i]... */
		    memcpy (&z[i], llc_buf_ptr, (1) * sizeof ((&z[i])[0]));
		    llc_buf_ptr += (1) * sizeof ((&z[i])[0]);

		    /* Unpacking &r[i]... */
		    memcpy (&r[i], llc_buf_ptr, (1) * sizeof ((&r[i])[0]));
		    llc_buf_ptr += (1) * sizeof ((&r[i])[0]);


		  }
	      }
	  }
	free (llc_buf);
      }
  }

/* End template: forall_comm_res_unit.tmpl */
/* Begin template: forall_exit.tmpl */

  free (llc_F);
  llc_F = NULL;

/* End template: forall_exit.tmpl */

  *_cols = cols;
  *_i = i;

}
